package com.tools.commons.base;


import cn.hutool.extra.servlet.ServletUtil;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.tools.security.base.RequestMethodEnum;
import com.tools.commons.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Set;

@Slf4j
public class BaseInterceptor extends HandlerInterceptorAdapter {
    private final PathMatcher pathMatcher = new AntPathMatcher();
    private final Map<String, Set<String>> anonymousUrls = Maps.newHashMap();
    private static final String[] staticResource = {".jpg", ".png", ".css", ".js", ".html", ".htm", ".gif", ".ttf"};
    private static final String GET = "GET";

    public boolean matches(HttpServletRequest request) {
        if (log.isDebugEnabled()) {
            log.debug("Request URL: [{}], URI: [{}], Request Method: [{}], IP: [{}]",
                    request.getRequestURL(),
                    request.getRequestURI(),
                    request.getMethod(),
                    ServletUtil.getClientIP(request));
        }
        String requestMethod = request.getMethod();
        String reqUrl = request.getRequestURI();

        if (StringUtils.equalsIgnoreCase(GET, requestMethod)) {
            for (String suffix : staticResource) {
                if (reqUrl.endsWith(suffix))
                    return true;
            }
        }

        RequestMethodEnum method = RequestMethodEnum.valueOf(requestMethod);
        Set<String> urls = anonymousUrls.get(method.getType());
        for (String url : urls) {
            if (this.pathMatcher.match(url, reqUrl))
                return true;
        }
        return false;
    }


    /**
     * 判断url 是否需要拦截
     *
     * @param request  request
     * @param response response
     * @param handler  handler
     * @return true 不需要拦截 false 需要拦截
     * @throws Exception Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Request URL: [{}], URI: [{}], Request Method: [{}], IP: [{}]",
                    request.getRequestURL(),
                    request.getRequestURI(),
                    request.getMethod(),
                    ServletUtil.getClientIP(request));
        }
        return matches(request);
    }

    public ConfigInterceptor antMatchers(HttpMethod method, String... antPatterns) {
        return new ConfigInterceptor(this, method, antPatterns);
    }

    public ConfigInterceptor antMatchers(HttpMethod method, Set<String> antPatterns) {
        return new ConfigInterceptor(this, method, antPatterns);
    }

    public ConfigInterceptor antMatchers(String... antPatterns) {
        return new ConfigInterceptor(this, null, antPatterns);
    }

    public ConfigInterceptor antMatchers(Set<String> antPatterns) {
        return new ConfigInterceptor(this, null, antPatterns);
    }

    public static class ConfigInterceptor {
        private final BaseInterceptor baseInterceptor;
        private final Set<String> urls;
        private final RequestMethodEnum method;

        public ConfigInterceptor(BaseInterceptor baseInterceptor, HttpMethod method, String... antPatterns) {
            this(baseInterceptor, method, Sets.newHashSet(antPatterns));
        }

        public ConfigInterceptor(BaseInterceptor baseInterceptor, HttpMethod method, Set<String> antPatterns) {
            this.baseInterceptor = baseInterceptor;
            this.method = RequestMethodEnum.find(method);
            this.urls = antPatterns != null ? antPatterns : Sets.newHashSet();
        }

        public BaseInterceptor permitAll() {
            baseInterceptor.anonymousUrls.put(method.getType(), urls);
            return baseInterceptor;
        }
    }
}
